#include "../src/storage/file_system.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

// Test utility functions
static void test_print(const char* test_name, int success) {
    printf("[%s] %s\n", success ? "PASS" : "FAIL", test_name);
}

static int cleanup_test_dir(const char* dir) {
    char cmd[512];
    snprintf(cmd, sizeof(cmd), "rm -rf %s", dir);
    return system(cmd);
}

// Test file system initialization
static int test_fs_initialization() {
    printf("\n=== Testing File System Initialization ===\n");
    
    const char* test_dir = "./test_fs";
    int success = 1;
    
    // Clean up any existing test directory
    cleanup_test_dir(test_dir);
    
    // Create test directory
    if (fs_create_directory(test_dir) != PAGE_OK) {
        printf("Failed to create test directory\n");
        return 0;
    }
    
    // Initialize file system
    file_system* fs = fs_init(test_dir);
    test_print("File System Initialization", fs != NULL);
    
    if (fs) {
        // Test file integrity
        int integrity_result = fs_verify_integrity(fs);
        test_print("File System Integrity", integrity_result == PAGE_OK);
        
        if (integrity_result != PAGE_OK) {
            success = 0;
        }
        
        // Print statistics
        fs_print_stats(fs);
        
        // Clean up
        fs_cleanup(fs);
    } else {
        success = 0;
    }
    
    // Clean up
    cleanup_test_dir(test_dir);
    
    return success;
}

// Test page operations
static int test_page_operations() {
    printf("\n=== Testing Page Operations ===\n");
    
    const char* test_dir = "./test_fs_pages";
    int success = 1;
    
    // Clean up any existing test directory
    cleanup_test_dir(test_dir);
    fs_create_directory(test_dir);
    
    // Initialize file system
    file_system* fs = fs_init(test_dir);
    if (!fs) {
        printf("Failed to initialize file system for page tests\n");
        cleanup_test_dir(test_dir);
        return 0;
    }
    
    // Test page allocation
    uint32_t page_id = 0;
    int alloc_result = fs_allocate_page(fs, &page_id);
    test_print("Page Allocation", alloc_result == PAGE_OK);
    
    if (alloc_result == PAGE_OK) {
        // Test page write
        gudb_page test_page;
        memset(&test_page, 0, GUDB_PAGE_SIZE);
        test_page.lsn = fs_get_next_lsn(fs);
        test_page.flags = FLAG_DIRTY;
        test_page.free_space = GUDB_PAGE_SIZE - 100; // Simulate some data
        strcpy((char*)test_page.data, "Hello, GuDB File System!");
        
        // Calculate checksum
        test_page.checksum = fs_calculate_checksum(&test_page);
        
        int write_result = fs_write_page(fs, page_id, &test_page);
        test_print("Page Write", write_result == PAGE_OK);
        
        if (write_result == PAGE_OK) {
            // Test page read
            gudb_page read_page;
            memset(&read_page, 0, GUDB_PAGE_SIZE);
            
            int read_result = fs_read_page(fs, page_id, &read_page);
            test_print("Page Read", read_result == PAGE_OK);
            
            if (read_result == PAGE_OK) {
                // Validate page content
                bool content_valid = (strcmp((char*)read_page.data, "Hello, GuDB File System!") == 0);
                test_print("Page Content Validation", content_valid);
                
                // Test page validation
                bool page_valid = fs_validate_page(&read_page);
                test_print("Page Checksum Validation", page_valid);
                
                if (!content_valid || !page_valid) {
                    success = 0;
                }
            } else {
                success = 0;
            }
        } else {
            success = 0;
        }
        
        // Test page free
        int free_result = fs_free_page(fs, page_id);
        test_print("Page Free", free_result == PAGE_OK);
        
        if (free_result != PAGE_OK) {
            success = 0;
        }
    } else {
        success = 0;
    }
    
    // Print final statistics
    printf("\nFile System Statistics after page operations:\n");
    fs_print_stats(fs);
    
    // Clean up
    fs_cleanup(fs);
    cleanup_test_dir(test_dir);
    
    return success;
}

// Test LSN management
static int test_lsn_management() {
    printf("\n=== Testing LSN Management ===\n");
    
    const char* test_dir = "./test_fs_lsn";
    int success = 1;
    
    // Clean up and setup
    cleanup_test_dir(test_dir);
    fs_create_directory(test_dir);
    
    file_system* fs = fs_init(test_dir);
    if (!fs) {
        printf("Failed to initialize file system for LSN tests\n");
        cleanup_test_dir(test_dir);
        return 0;
    }
    
    // Test LSN generation
    uint64_t lsn1 = fs_get_next_lsn(fs);
    uint64_t lsn2 = fs_get_next_lsn(fs);
    uint64_t lsn3 = fs_get_next_lsn(fs);
    
    bool lsn_monotonic = (lsn1 < lsn2) && (lsn2 < lsn3);
    test_print("LSN Monotonic Increase", lsn_monotonic);
    
    // Test page LSN operations
    gudb_page test_page;
    memset(&test_page, 0, GUDB_PAGE_SIZE);
    
    int set_lsn_result = fs_set_page_lsn(&test_page, lsn1);
    test_print("Set Page LSN", set_lsn_result == PAGE_OK);
    
    uint64_t retrieved_lsn = fs_get_page_lsn(&test_page);
    bool lsn_match = (retrieved_lsn == lsn1);
    test_print("Get Page LSN", lsn_match);
    
    if (!lsn_monotonic || set_lsn_result != PAGE_OK || !lsn_match) {
        success = 0;
    }
    
    // Clean up
    fs_cleanup(fs);
    cleanup_test_dir(test_dir);
    
    return success;
}

// Test file locking
static int test_file_locking() {
    printf("\n=== Testing File Locking ===\n");
    
    const char* test_dir = "./test_fs_lock";
    int success = 1;
    
    // Clean up and setup
    cleanup_test_dir(test_dir);
    fs_create_directory(test_dir);
    
    file_system* fs = fs_init(test_dir);
    if (!fs) {
        printf("Failed to initialize file system for lock tests\n");
        cleanup_test_dir(test_dir);
        return 0;
    }
    
    // The database should be locked automatically during init
    // Try to create another file system instance (should fail due to lock)
    file_system* fs2 = fs_init(test_dir);
    bool lock_prevents_second_instance = (fs2 == NULL);
    test_print("File Lock Prevents Second Instance", lock_prevents_second_instance);
    
    if (fs2) {
        fs_cleanup(fs2); // Clean up if somehow it succeeded
        success = 0;
    }
    
    // Test unlock and relock
    int unlock_result = fs_unlock_database(fs);
    test_print("Database Unlock", unlock_result == PAGE_OK);
    
    int lock_result = fs_lock_database(fs);
    test_print("Database Relock", lock_result == PAGE_OK);
    
    if (unlock_result != PAGE_OK || lock_result != PAGE_OK) {
        success = 0;
    }
    
    // Clean up
    fs_cleanup(fs);
    cleanup_test_dir(test_dir);
    
    return success;
}

// Test checksum operations
static int test_checksum_operations() {
    printf("\n=== Testing Checksum Operations ===\n");
    
    int success = 1;
    
    // Create test page
    gudb_page test_page;
    memset(&test_page, 0, GUDB_PAGE_SIZE);
    test_page.lsn = 12345;
    test_page.flags = FLAG_DIRTY | FLAG_COMPRESS;
    test_page.free_space = 3000;
    strcpy((char*)test_page.data, "Test data for checksum validation");
    
    // Calculate checksum
    uint32_t checksum1 = fs_calculate_checksum(&test_page);
    test_page.checksum = checksum1;
    
    // Validate page
    bool valid1 = fs_validate_page(&test_page);
    test_print("Page Validation with Correct Checksum", valid1);
    
    // Corrupt the page
    test_page.data[0] = 'X'; // Change first byte
    bool valid2 = fs_validate_page(&test_page);
    test_print("Page Validation with Corrupted Data", !valid2);
    
    // Repair the page
    test_page.data[0] = 'T'; // Restore first byte
    int repair_result = fs_repair_page(&test_page);
    test_print("Page Repair", repair_result == PAGE_OK);
    
    // Validate repaired page
    bool valid3 = fs_validate_page(&test_page);
    test_print("Page Validation after Repair", valid3);
    
    if (!valid1 || valid2 || repair_result != PAGE_OK || !valid3) {
        success = 0;
    }
    
    return success;
}

// Main test runner
int main() {
    printf("GuDB File System Module Tests\n");
    printf("=============================\n");
    
    int total_tests = 0;
    int passed_tests = 0;
    
    // Run all test suites
    struct {
        const char* name;
        int (*test_func)(void);
    } test_suites[] = {
        {"File System Initialization", test_fs_initialization},
        {"Page Operations", test_page_operations},
        {"LSN Management", test_lsn_management},
        {"File Locking", test_file_locking},
        {"Checksum Operations", test_checksum_operations}
    };
    
    int num_suites = sizeof(test_suites) / sizeof(test_suites[0]);
    
    for (int i = 0; i < num_suites; i++) {
        printf("\nRunning test suite: %s\n", test_suites[i].name);
        
        int suite_result = test_suites[i].test_func();
        total_tests++;
        
        if (suite_result) {
            passed_tests++;
            printf("Suite PASSED: %s\n", test_suites[i].name);
        } else {
            printf("Suite FAILED: %s\n", test_suites[i].name);
        }
    }
    
    // Print summary
    printf("\n========================================\n");
    printf("Test Results: %d/%d suites passed\n", passed_tests, total_tests);
    
    if (passed_tests == total_tests) {
        printf("All tests PASSED!\n");
        return 0;
    } else {
        printf("Some tests FAILED!\n");
        return 1;
    }
}